/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.tabbedproperties.composites;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory;
import org.eclipse.uml2.common.edit.command.ChangeCommand;
import org.eclipse.uml2.common.util.CacheAdapter;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.InstanceValue;
import org.eclipse.uml2.uml.LiteralBoolean;
import org.eclipse.uml2.uml.LiteralInteger;
import org.eclipse.uml2.uml.LiteralSpecification;
import org.eclipse.uml2.uml.LiteralString;
import org.eclipse.uml2.uml.LiteralUnlimitedNatural;
import org.eclipse.uml2.uml.OpaqueExpression;
import org.eclipse.uml2.uml.PrimitiveType;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Slot;
import org.eclipse.uml2.uml.StructuralFeature;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.ValueSpecification;

import com.cea.papyrus.core.commands.EMFtoGEFWrapCommand;
import com.cea.papyrus.core.commands.MoveInListCommand;
import com.cea.papyrus.core.editor.CommandStackUtils;
import com.cea.papyrus.core.editpart.GraphNodeWithSemanticEditPart;
import com.cea.papyrus.core.listener.UmlElementListener;
import com.cea.papyrus.core.ui.dialogs.ChooseInstanceSpecificationDialog;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagram.classdiagram.tabbedproperties.section.ValueSpecificationKind;
import com.cea.papyrus.profile.Message;
import com.cea.papyrus.profile.ui.dialogs.InputDialogEnumeration;
import com.cea.papyrus.profile.ui.dialogs.InputDialogPrimitiveType;
import com.cea.papyrus.profile.utils.Util;
import com.cea.papyrus.umlutils.Element;
import com.cea.papyrus.umlutils.ValueSpecificationUtil;

/**
 * Composite that displays the possible values of a slot
 */
public class SlotComposite extends DecoratedTableComposite implements ISectionComposite {
	
	/** The slot value listener */
	protected MouseListener slotValueListener;
	
	/** The associated edit part */
	protected GraphNodeWithSemanticEditPart graphNodeWithSemanticEditPart;
	
	/** key to access UML Data from table items */ 
	private final static String KEY = "slot_data";

	/** debug channel */
	protected static final int channel = 21;
	
	/** Slot for which values are displayed.*/
	private Slot umlSlot;

	/** key for data in the menu for Value Specification Kind choice button*/
	protected static final String VALUE_SPEC_DATA = "value_spec_data";
	
	/** Menu for the value specification type choice button */
	protected Menu menu;
	
	/**
	 * Default Constructor.
	 */
	public SlotComposite() {
		super("Slot values");
		this.slotValueListener = new SlotValueEditingListener();
	
	}

	/**
	 * Sets the edit part associated to this composite
	 * @param graphNodeWithSemanticEditPart the edit part which controls the slot
	 */
	public void setEditPart(GraphNodeWithSemanticEditPart graphNodeWithSemanticEditPart){
		this.graphNodeWithSemanticEditPart=graphNodeWithSemanticEditPart;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.composites.DecoratedTableComposite#createContent(org.eclipse.swt.widgets.Composite, org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory)
	 */
	@Override
	public Composite createContent(Composite parent, TabbedPropertySheetWidgetFactory factory) {
		Composite composite = super.createContent(parent, factory);
		table.addMouseListener(slotValueListener);
		addButton.removeMouseListener(addButtonlistener);
		return composite;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.composites.DecoratedTableComposite#setElement(com.cea.papyrus.umlutils.Element)
	 */
	@Override
	public void setElement(Element element) {
		super.setElement(element);
		this.umlSlot = (Slot)element.getUml2Element();
	}
	
	/**
	 * Returns current displayed Slot 
	 * @return current displayed Slot 
	 */
	public Slot getSlot() {
		return umlSlot;
	}
	
	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.composites.DecoratedTableComposite#refresh()
	 */
	@Override
	public void refresh() {
		// check elements are not disposed
		if ( (!removeButton.isDisposed())&&
				(!addButton.isDisposed())&&
				(!upButton.isDisposed())&&
				(!downButton.isDisposed()) ) {
			
			// check that the slot has a defining feature.
			// if not, no values can be added/removed/etc.
			if(umlSlot.getDefiningFeature()==null){
				addButton.setEnabled(false);
				removeButton.setEnabled(false);
				upButton.setEnabled(false);
				downButton.setEnabled(false);
			}
			// a defining feature is associated to the slot, values can be modified
			else {
				addButton.setEnabled(true);
				removeButton.setEnabled(true);
				upButton.setEnabled(true);
				downButton.setEnabled(true);
			}

			if(menu==null || !menu.isDisposed()) {
				createMenuForValueSpecificationChoiceButton();
			}
			
			// fill the table
			if(!table.isDisposed()&& (umlSlot!=null)){
				// Remove parameters from table 
				table.removeAll();

				// Read and add parameter
				Iterator<ValueSpecification> it = umlSlot.getValues().iterator();
				while (it.hasNext()) {
					ValueSpecification currentValue = it.next();
					TableItem item = new TableItem(table, SWT.BORDER);
					// choose the icon corresponding to the instance of the classifier
					if(getLabelProvider()!=null) {
						item.setImage(getLabelProvider().getImage(currentValue));
					}
					//item.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(currentValue));
					item.setData(KEY, currentValue);
					item.setText(getLabel(currentValue));
				}
				table.setToolTipText("Double click on a value to edit it");
			}
		}

	}
	
	
	/**
	 * Gets the label for the given ValueSpecification
	 * @param valueSpecification the displayed value specification
	 * @return the label computed for the given ValueSpecification
	 */
	private String getLabel(ValueSpecification valueSpecification){
		String label="";
		
		Type type = umlSlot.getDefiningFeature().getType();
		// String typeName = type.getName();
		
		if(valueSpecification instanceof OpaqueExpression){
			if(!((OpaqueExpression)valueSpecification).getBodies().isEmpty() && !((OpaqueExpression)valueSpecification).getLanguages().isEmpty() ) {
				label += "{"+((OpaqueExpression)valueSpecification).getLanguages().get(0)+"} "+((OpaqueExpression)valueSpecification).getBodies().get(0);
			}
		} else if(valueSpecification instanceof LiteralInteger) {
			label += String.valueOf(((LiteralInteger)valueSpecification).getValue());
		} else if(valueSpecification instanceof LiteralUnlimitedNatural) {
			label += String.valueOf(((LiteralUnlimitedNatural)valueSpecification).getValue());
		}else if(valueSpecification instanceof LiteralBoolean) {
			label += String.valueOf(((LiteralBoolean)valueSpecification).isValue());
		} else if(valueSpecification instanceof LiteralString) {
			label += ((LiteralString)valueSpecification).getValue();
		}
		// InstanceValue
		else if(type instanceof Classifier){
			InstanceSpecification is = ((InstanceValue)valueSpecification).getInstance();
			if(is!=null)
				label += is.getLabel() + ": "+type.getName()+"  ["+is.getQualifiedName()+"]";
		}
		
		return label;
	}
	
	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.composites.DecoratedTableComposite#addButtonPressed()
	 */
	@Override
	public void addButtonPressed() {
		// check the slot is nbot null
		if (umlSlot==null) {
			// Nothing selected
			return;
		}
		// Retrieve slot related info
		StructuralFeature definingFeature = umlSlot.getDefiningFeature();
		if(definingFeature==null) {
			return;
		}
		
		// retrieves other values
		int lower = definingFeature.getLower();
		int upper = definingFeature.getUpper();
		Type type = definingFeature.getType();

		// if lower multiplicity is equal to upper multiplicity : cannot add
		if ((lower == upper) && (umlSlot.getValues().size() == upper)) {
			Message.warning(
					"Multiplicity of this slot is"
					+ lower+".."
					+ upper+"\n"
					+ "Impossible to add a new value.");
			return;
		}

		// Retrieve current value
		EList currentValues = null;

		if (definingFeature.isMultivalued() || (umlSlot.getValues().size() < upper)) {
			Object newValue = null;
			String dialogValue = "";
			
			/** primitive type **/
			if (type instanceof PrimitiveType) {
				
				// Create dialog box for value to add
				InputDialogPrimitiveType valueDialog = new InputDialogPrimitiveType(getMainComposite().getShell(), (Property)definingFeature, null, -1);
				int val = valueDialog.open();

				// Treat Cancel case first
				if (val == InputDialogPrimitiveType.CANCEL) {
					// Close dialog box
					valueDialog.close();
					// And quit
					return;
				}

				// New object as string (user input)
				dialogValue = valueDialog.getValue();
				// Treat dialogValue
				newValue = Util.getValueObjectFromString(dialogValue, type);
				valueDialog.close();
			}
			
			/** Enumeration **/
			else if (type instanceof Enumeration) {

				// Create and Open combo box
				InputDialogEnumeration valueDialog = new InputDialogEnumeration(getMainComposite().getShell(), (Property)definingFeature, null, -1);
				int val = valueDialog.open();
				
				if ((val == InputDialogEnumeration.OK) && (valueDialog.getSelectionIndex() != -1)) {
					int index = valueDialog.getSelectionIndex();	
					newValue = ((Enumeration) type).getOwnedLiterals().get(index);
				}
				valueDialog.close();
			}
			
			/** Classifier **/
			else if (type instanceof Classifier) {
				ChooseInstanceSpecificationDialog instanceDialog = new ChooseInstanceSpecificationDialog(getMainComposite().getShell(), (Classifier)type, umlSlot);
				int val = instanceDialog.open();
				
				if(val == ChooseInstanceSpecificationDialog.OK){
					newValue = instanceDialog.getResult();
				}
				instanceDialog.close();
			}
			
			// new value entered ?
			if (newValue == null) {
				// Refresh && quit
				refresh();
				return;
			}

			// Update property value(s)
			if (definingFeature.isMultivalued()) {
				addValueSpecification(type, newValue);
			// otherwise
			} else {
				umlSlot.getValues().clear();
				addValueSpecification(type, newValue);
			}
			
			// Update tree && Refresh
			refresh();
			// Force model change

		} else {
			Message.warning(
					"Upper multiplicity of "
					+definingFeature.getName()+
					" is "
					+upper);
		}
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.composites.DecoratedTableComposite#downButtonPressed()
	 */
	/**
	 * Down button pressed.
	 */
	@Override
	public void downButtonPressed() {
		CompoundCommand compoundCommand = new CompoundCommand();
		TableItem[] tableItems = table.getSelection();

		for(int i = (tableItems.length-1); i >= 0; i--) {
			// get use cases list
			List values = umlSlot.getValues();
			// get use case
			ValueSpecification currentValue = (ValueSpecification) tableItems[i].getData(KEY);
			int newIndex = table.indexOf(tableItems[i]) + 1;
			if(newIndex < values.size()) {
				//new MoveInListCommand(parameters, parameter, newIndex).execute();
				compoundCommand.add(new MoveInListCommand(values, currentValue, newIndex));
			}
		}
		CommandStack stack = CommandStackUtils.getCommandStack();
		Assert.isNotNull(stack, "Impossible to adapt current editor into a CommandStack");
		stack.execute(compoundCommand);
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.composites.DecoratedTableComposite#editItem(org.eclipse.swt.widgets.TableItem)
	 */
	/**
	 * Edits the item.
	 * 
	 * @param item the item
	 */
	@Override
	public void editItem(TableItem item) {
		if (item == null) {
			return;
		}
		// e linked to the item
		ValueSpecification value = (ValueSpecification)item.getData(KEY);

		// TODO edit a classifier
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.composites.DecoratedTableComposite#removeButtonPressed()
	 */
	/**
	 * Removes the button pressed.
	 */
	@Override
	public void removeButtonPressed() {
		// get selection and remove it
		TableItem[] tableItems = table.getSelection();
		for(int i = 0; i < tableItems.length ; i++) {
			// get use case remove umlClassifier from its subject list 
			// and removed it from the use case list
			ValueSpecification valueSpec = (ValueSpecification) tableItems[i].getData(KEY);
			umlSlot.getValues().remove(valueSpec);
		}
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.composites.DecoratedTableComposite#upButtonPressed()
	 */
	/**
	 * Up button pressed.
	 */
	@Override
	public void upButtonPressed() {
		CompoundCommand compoundCommand = new CompoundCommand();
		TableItem[] tableItems = table.getSelection();
		// get extension point list
		List values = umlSlot.getValues();
		// get extension point
		for(int i = 0; i < tableItems.length ; i++) {
			// get use case
			ValueSpecification valueSpec = (ValueSpecification) tableItems[i].getData(KEY);
			int newIndex = table.indexOf(tableItems[i]) - 1;
			if (newIndex >= 0) {
				compoundCommand.add(new MoveInListCommand(values, valueSpec, newIndex));
			}
		}
		CommandStack stack = CommandStackUtils.getCommandStack();
		Assert.isNotNull(stack, "Impossible to adapt current editor into a CommandStack");
		stack.execute(compoundCommand);
	}
	
	/**
	 * This method creates the approriate value specification for the given type and values it with value.
	 * 
	 * @param value the value
	 * @param type the type
	 */
	private void addValueSpecification(Type type, Object value){
		String typeName = type.getName();
		ValueSpecification result=null;
		 UmlElementListener _adapter=null ;
		 if( this.graphNodeWithSemanticEditPart!=null){
		 _adapter=new UmlElementListener(this.graphNodeWithSemanticEditPart);
		 }
		 
		// primitive type ==> LiteralSpecification
		if(type instanceof PrimitiveType){
			if(typeName.equals("Integer")){
				LiteralInteger literalInteger = UMLFactory.eINSTANCE.createLiteralInteger();
				result = umlSlot.createValue("", type, literalInteger.eClass());
				if( _adapter!=null){
					((Notifier)(result)).eAdapters().add(_adapter);
				}
				((LiteralInteger)result).setValue(Integer.valueOf(value.toString()));

			}
			
			else if(typeName.equals("UnlimitedNatural")){
				LiteralUnlimitedNatural literalUnlimitedNatural = UMLFactory.eINSTANCE.createLiteralUnlimitedNatural();
				result = umlSlot.createValue("", type, literalUnlimitedNatural.eClass());
				if( _adapter!=null){
					((Notifier)(result)).eAdapters().add(_adapter);
				}
				((LiteralUnlimitedNatural)result).setValue(Integer.valueOf(value.toString()));
			}
			
			else if(typeName.equals("Boolean")){
				LiteralBoolean literalBoolean = UMLFactory.eINSTANCE.createLiteralBoolean();
				result = umlSlot.createValue("", type, literalBoolean.eClass());
				if( _adapter!=null){
					((Notifier)(result)).eAdapters().add(_adapter);
				}
				((LiteralBoolean)result).setValue(Boolean.valueOf(value.toString()));
			}
			
			else /*if(typeName.equals("String"))*/{
				LiteralString literalString = UMLFactory.eINSTANCE.createLiteralString();
				result = umlSlot.createValue("", type, literalString.eClass());
				if( _adapter!=null){
					((Notifier)(result)).eAdapters().add(_adapter);
				}
				((LiteralString)result).setValue(value.toString());
			}

		}
		
		//else ==> instance value
		else if (type instanceof Classifier){
			InstanceValue instanceValue = UMLFactory.eINSTANCE.createInstanceValue();
			result = umlSlot.createValue("", type, instanceValue.eClass());
			if( _adapter!=null){
				((Notifier)(result)).eAdapters().add(_adapter);
			}
			((InstanceValue)result).setInstance((InstanceSpecification)value);
			
		}
		
		else {
			Debug.error(this, "unknow type: "+type, channel);
		}
	}
	
	/**
	 * The Class SlotValueEditingListener.
	 */
	private class SlotValueEditingListener implements MouseListener {
		
		/**
		 * Mouse double click.
		 * 
		 * @param e the e
		 */
		public void mouseDoubleClick(MouseEvent e) {
			slotValueEditing();
		}
		
		/**
		 * Mouse down.
		 * 
		 * @param e the e
		 */
		public void mouseDown(MouseEvent e) {
			// do nothing
		}
		
		/**
		 * Mouse up.
		 * 
		 * @param e the e
		 */
		public void mouseUp(MouseEvent e) {
		}
	}
	
	/**
	 * This method handles slot's value editing.
	 */
	protected void slotValueEditing() {
		
		Object valueToEdit = table.getSelection()[0].getData(KEY);
		
		if(valueToEdit instanceof ValueSpecification){

			Type type = umlSlot.getDefiningFeature().getType();
			StructuralFeature definingFeature = umlSlot.getDefiningFeature();
			
			if(valueToEdit instanceof LiteralSpecification){
				// Boolean value
				if(valueToEdit instanceof LiteralBoolean){
					String dialogValue = "";
					// Create dialog box for value to add
					InputDialogPrimitiveType valueDialog = new InputDialogPrimitiveType(getMainComposite().getShell(), (Property)definingFeature, ((LiteralBoolean)valueToEdit).isValue(), -1);
					int val = valueDialog.open();

					// Treat Cancel case first
					if (val == InputDialogPrimitiveType.CANCEL) {
						// Close dialog box
						valueDialog.close();
						// And quit
						return;
					}

					// New object as string (user input)
					dialogValue = valueDialog.getValue();
					// Treat dialogValue
					Object value = Util.getValueObjectFromString(dialogValue, type);
					valueDialog.close();

					
					((LiteralBoolean)valueToEdit).setValue(Boolean.valueOf(value.toString()));
				}
				
				// Integer value
				else if(valueToEdit instanceof LiteralInteger){
					String dialogValue = "";
					// Create dialog box for value to add
					InputDialogPrimitiveType valueDialog = new InputDialogPrimitiveType(getMainComposite().getShell(), (Property)definingFeature, ((LiteralInteger)valueToEdit).getValue(), -1);
					int val = valueDialog.open();

					// Treat Cancel case first
					if (val == InputDialogPrimitiveType.CANCEL) {
						// Close dialog box
						valueDialog.close();
						// And quit
						return;
					}

					// New object as string (user input)
					dialogValue = valueDialog.getValue();
					// Treat dialogValue
					Object value = Util.getValueObjectFromString(dialogValue, type);
					valueDialog.close();

					((LiteralInteger)valueToEdit).setValue(Integer.valueOf(value.toString()));
				}
				
				// UnlimitedNatural value
				else if(valueToEdit instanceof LiteralUnlimitedNatural){
					String dialogValue = "";
					// Create dialog box for value to add
					InputDialogPrimitiveType valueDialog = new InputDialogPrimitiveType(getMainComposite().getShell(), (Property)definingFeature, ((LiteralUnlimitedNatural)valueToEdit).getValue(), -1);
					int val = valueDialog.open();

					// Treat Cancel case first
					if (val == InputDialogPrimitiveType.CANCEL) {
						// Close dialog box
						valueDialog.close();
						// And quit
						return;
					}

					// New object as string (user input)
					dialogValue = valueDialog.getValue();
					// Treat dialogValue
					Object value = Util.getValueObjectFromString(dialogValue, type);
					valueDialog.close();

					((LiteralUnlimitedNatural)valueToEdit).setValue(Integer.valueOf(value.toString()));
				}
				
				// String value
				else if(valueToEdit instanceof LiteralString){
					String dialogValue = "";
					// Create dialog box for value to add
					InputDialogPrimitiveType valueDialog = new InputDialogPrimitiveType(getMainComposite().getShell(), (Property)definingFeature, ((LiteralString)valueToEdit).getValue(), -1);
					int val = valueDialog.open();

					// Treat Cancel case first
					if (val == InputDialogPrimitiveType.CANCEL) {
						// Close dialog box
						valueDialog.close();
						// And quit
						return;
					}

					// New object as string (user input)
					dialogValue = valueDialog.getValue();
					// Treat dialogValue
					Object value = Util.getValueObjectFromString(dialogValue, type);
					valueDialog.close();

					((LiteralString)valueToEdit).setValue(value.toString());
				}
				
				
			}
			
			else if(valueToEdit instanceof InstanceValue){
				// Enumeration
				if(type instanceof Enumeration){
					// Create and Open combo box
					InputDialogEnumeration valueDialog = new InputDialogEnumeration(getMainComposite().getShell(), (Property)definingFeature, null, -1);
					int val = valueDialog.open();
					Object value = null;
					// Treat Cancel case first
					if (val == InputDialogEnumeration.CANCEL) {
						// Close dialog box
						valueDialog.close();
						// And quit
						return;
					}

					if ((val == InputDialogEnumeration.OK) && (valueDialog.getSelectionIndex() != -1)) {
						int index = valueDialog.getSelectionIndex();	
						value = ((Enumeration) type).getOwnedLiterals().get(index);
					}
					valueDialog.close();
					
					((InstanceValue)valueToEdit).setInstance((InstanceSpecification)value);
				}
				
				else {
					ChooseInstanceSpecificationDialog instanceDialog = new ChooseInstanceSpecificationDialog(getMainComposite().getShell(), (Classifier)type, umlSlot);
					int val = instanceDialog.open();
					Object value = null;
					// Treat Cancel case first
					if (val == ChooseInstanceSpecificationDialog.CANCEL) {
						// Close dialog box
						instanceDialog.close();
						// And quit
						return;
					}
					
					if(val == ChooseInstanceSpecificationDialog.OK){
						value = instanceDialog.getResult();
					}
					instanceDialog.close();
					
					((InstanceValue)valueToEdit).setInstance((InstanceSpecification)value);
				}
			}
			
			// refresh values
			refresh();
		}
				
		else {
			Debug.error(this, "Unknown value!!!!", channel);
		}
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void dispose(){
		super.dispose();
		if(table!=null && !table.isDisposed())
			table.removeMouseListener(slotValueListener);
	}
	
	/**
	 * Adds the menu to the add button
	 */
	protected void createMenuForValueSpecificationChoiceButton() {
		SpecificationTypeSelectionListener selectionTypelistener = new SpecificationTypeSelectionListener();
		menu = new Menu(addButton);
		menu.setEnabled(true) ;
		for (ValueSpecificationKind valueSpecKind : ValueSpecificationKind.values()) {
			if(checkValueSpecificationConstraint(valueSpecKind)) {
				MenuItem item = new MenuItem(menu, SWT.BORDER);
				if(valueSpecKind.getMetaclass() == null) {
					item.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE));
				}
				item.setText(valueSpecKind.getName());
				item.setData(VALUE_SPEC_DATA, valueSpecKind);
				item.addSelectionListener(selectionTypelistener);
			}
		}

		addButton.addSelectionListener(new SelectionListener() {

			/**
			 * {@inheritDoc}
			 */
			public void widgetDefaultSelected(SelectionEvent e) {
			}

			/**
			 * {@inheritDoc}
			 */
			public void widgetSelected(SelectionEvent e) {
				menu.setVisible(true);	
			}

		});
	}
	
	/**
	 * Check if the value specification is available for the type of element
	 * @param valueSpecKind the value specification to check
	 * @return <code>true</code> if this kind of ValueSpecification can be used for this type of element
	 */
	protected boolean checkValueSpecificationConstraint(ValueSpecificationKind valueSpecKind) {
		return (valueSpecKind!=ValueSpecificationKind.NONE);
	}

	/**
	 * Listener for the CCombo selection composite, to change the default value implementation
	 */
	protected class SpecificationTypeSelectionListener implements SelectionListener {

		/**
		 * {@inheritDoc}
		 */
		public void widgetDefaultSelected(SelectionEvent e) {
		}

		/**
		 * {@inheritDoc}
		 */
		public void widgetSelected(SelectionEvent e) {
			// retrieve the value specification
			final ValueSpecificationKind valueSpecKind = (ValueSpecificationKind)((MenuItem)e.widget).getData(VALUE_SPEC_DATA);

			final AdapterFactoryEditingDomain emfDomain = getModelManager().getDiResourceSet().getEditingDomain();
			EMFtoGEFWrapCommand command = new EMFtoGEFWrapCommand(emfDomain) {
				@Override
				public org.eclipse.emf.common.command.Command createEMFCommand() {
					return new ChangeCommand(emfDomain, new Runnable() {
						public void run() {
							// owner of the default Value
							Slot container = getSlot() ;

							//3. crates the new Value specification, according to the selection
							// creates the new one if one exists
							if(!ValueSpecificationKind.NONE.equals(valueSpecKind)) {	// does not treat NONE, as nothing can be created
								// creates the default value
								ValueSpecification newSpecif = (ValueSpecification)UMLFactory.eINSTANCE.create(valueSpecKind.getMetaclass());
								container.getValues().add(newSpecif);
							}
						}

					}, "Change Default Value Implementation", "Changes the element that defines the Default Value");
				}
			};
			CommandStackUtils.getCommandStack().execute(command);
			refresh();
		}
	}
	
}

